package coupon

import (
	sqlc "bp/db/sqlc"
	"bp/internal/render"
	sharedConv "bp/internal/rpcserver/shared/conv"
	sharedVld "bp/internal/rpcserver/shared/vld"
	"bp/internal/service/entity/coupon"
	"bp/internal/service/param"
	"bp/internal/util"
	couponGrpc "bp/rpc/gen/webapi/coupon"
	"context"
)

// VldCreateCouponReq 验证新建优惠券请求
func (s *CouponWebApiImp) VldCreateCouponReq(ctx context.Context, q *sqlc.Queries, req *couponGrpc.CreateCouponReq) (
	ptr *coupon.CreateCouponParam,
	itemCategoryConfPtrs param.ItemCategoryConfigurationPtrArray,
	itemConfPtrs param.ItemConfigurationPtrArray,
	err error) {
	slog := util.NewContextLogger(ctx, s.slog)
	token := util.GetBilinToken(ctx)

	if !sharedVld.IsOwnerType(req.OwnerType) {
		err = render.InvalidArgumentValue("owner_type")
		return
	}
	if req.OwnerId < 0 {
		err = render.InvalidArgumentRange("owner_id")
		return
	}
	if req.OwnerType == string(sqlc.EmOwnerTypeStore) && req.OwnerId == 0 {
		err = render.ArgumentMismatch("owner_type", "owner_id")
		return
	}
	if util.IsEmpty(req.Name) {
		err = render.ArgumentEmpty("name")
		return
	}
	if !sharedVld.IsCouponNature(req.Nature) {
		err = render.InvalidArgumentValue("nature")
		return
	}
	if !sharedVld.IsOfferCategory(req.OfferCategory) {
		err = render.InvalidArgumentValue("offer_category")
		return
	}
	if !sharedVld.IsOfferType(req.OfferType) {
		err = render.InvalidArgumentValue("offer_type")
		return
	}
	if req.NeedVerifyQualification {
		if !sharedVld.IsQualifyTypeArray(req.QualifyTypes, false) {
			err = render.InvalidArgumentValue("qualify_types")
			return
		}
	}
	if req.Price < 0 {
		err = render.InvalidArgumentRange("price")
		return
	}
	if req.Quota < 0 {
		err = render.InvalidArgumentRange("quota")
		return
	}
	if req.OffMaximum < 0 {
		err = render.InvalidArgumentRange("off_maximum")
		return
	}
	var offMaximum int32 = -1
	switch sqlc.EmOfferType(req.OfferType) {
	case sqlc.EmOfferTypeDiscount:
		if req.Price > 100 {
			err = render.InvalidArgumentRange("price[0,100]")
			return
		}
		if req.OffMaximum <= req.Quota {
			err = render.InvalidArgumentRange("off_maximum<=quota")
			return
		}
		if req.OffMaximum > 0 {
			offMaximum = req.OffMaximum
		}
	}
	if !sharedVld.IsCouponUsePeriodType(req.UsePeriodType) {
		err = render.InvalidArgumentValue("use_period_type")
		return
	}
	switch sqlc.EmCouponUsePeriodType(req.UsePeriodType) {
	case sqlc.EmCouponUsePeriodTypeSinceGot:
		if req.Days < 0 {
			err = render.InvalidArgumentRange("days")
			return
		}
		if req.AvailableAfterGotDays < 0 {
			err = render.InvalidArgumentRange("available_after_got_days")
			return
		}
	case sqlc.EmCouponUsePeriodTypeFixedDate:
		useBegined := sqlc.PBTimestampToGoTime(req.UseBegined)
		useEnded := sqlc.PBTimestampToGoTime(req.UseEnded)
		if useEnded.Before(useBegined) {
			err = render.InvalidArgumentRange("use_ended<=use_begined")
			return
		}
	}
	if !util.IsEmpty(req.DateChooseType) && !sharedVld.IsChooseType(req.DateChooseType) {
		err = render.InvalidArgumentValue("date_choose_type")
		return
	}
	if !sharedVld.IsOfferUseSceneArray(req.UseScenes, false) {
		err = render.InvalidArgumentValue("use_scenes")
		return
	}
	if !sharedVld.IsScope(req.Scope) {
		err = render.InvalidArgumentValue("scope")
		return
	}
	switch sqlc.EmScope(req.Scope) {
	case sqlc.EmScopeIncludeItemCategoriesExcludeItems:
		if len(req.ItemCategoryConfs) == 0 {
			err = render.ArgumentEmpty("item_category_confs")
		}
	case sqlc.EmScopeExcludeItemCategories:
		if len(req.ItemCategoryConfs) == 0 {
			err = render.ArgumentEmpty("item_category_confs")
		}
	case sqlc.EmScopeIncludeItems:
		if len(req.ItemConfs) == 0 {
			err = render.ArgumentEmpty("item_confs")
		}
	case sqlc.EmScopeExcludeItems:
		if len(req.ItemConfs) == 0 {
			err = render.ArgumentEmpty("item_confs")
		}
	}
	if req.Maximum < 0 {
		err = render.InvalidArgumentRange("maximum")
		return
	}
	if req.MaxiumGotFrequency < 0 {
		err = render.InvalidArgumentRange("maxium_got_frequency")
		return
	}

	ptr = &coupon.CreateCouponParam{
		CreateCouponParamsPtr: &sqlc.CreateCouponParams{
			BrandID:                 token.BrandID,
			OwnerType:               req.OwnerType,
			OwnerID:                 req.OwnerId,
			Name:                    req.Name,
			Desc:                    sqlc.NSFromString(req.Desc),
			Tags:                    req.Tags,
			Nature:                  req.Nature,
			OfferCategory:           req.OfferCategory,
			OfferType:               req.OfferType,
			Bg:                      sqlc.NSFromString(req.Bg),
			NeedVerifyQualification: req.NeedVerifyQualification,
			Price:                   req.Price,
			Quota:                   req.Quota,
			OffMaximum:              offMaximum,
			UsePeriodType:           req.UsePeriodType,
			UseTimeRanges:           sharedConv.ConvTimeRangeArrayPbToEntity(req.UseTimeRanges),
			DateChooseType:          sqlc.NSFromString(req.DateChooseType),
			Weekdays:                req.Weekdays,
			Monthdays:               req.Monthdays,
			UseScenes:               req.UseScenes,
			Scope:                   req.Scope,
			Maximum:                 req.Maximum,
			MaxiumGotFrequency:      req.MaxiumGotFrequency,
		},
	}

	if req.NeedVerifyQualification {
		slog.Infof("req.QualifyTypes=>%+v", req.QualifyTypes)
		ptr.CreateCouponParamsPtr.QualifyTypes = req.QualifyTypes
	}
	switch sqlc.EmCouponUsePeriodType(req.UsePeriodType) {
	case sqlc.EmCouponUsePeriodTypeSinceGot:
		ptr.CreateCouponParamsPtr.Days = sqlc.NInt32FromInt32(req.Days)
		ptr.CreateCouponParamsPtr.AvailableAfterGotDays = sqlc.NInt32FromInt32(req.AvailableAfterGotDays)
	case sqlc.EmCouponUsePeriodTypeFixedDate:
		ptr.CreateCouponParamsPtr.UseBegined = sqlc.PBTimestampToGoNTime(req.UseBegined)
		ptr.CreateCouponParamsPtr.UseEnded = sqlc.PBTimestampToGoNTime(req.UseEnded)
	}

	itemCategoryConfPtrs = sharedConv.ConvItemCategoryConfigurationPtrArrayPbToEntity(req.ItemCategoryConfs)
	itemConfPtrs = sharedConv.ConvItemConfigurationPtrArrayPbToEntity(req.ItemConfs)

	slog.Infof("coupon_imp/cmd_vld.VldCreateCouponReq ok")
	return
}

// VldUpdateCouponReq 验证更新优惠券请求
func (s *CouponWebApiImp) VldUpdateCouponReq(ctx context.Context, q *sqlc.Queries, req *couponGrpc.UpdateCouponReq) (
	ptr *coupon.UpdateCouponParam,
	itemCategoryConfPtrs param.ItemCategoryConfigurationPtrArray,
	itemConfPtrs param.ItemConfigurationPtrArray,
	err error) {
	slog := util.NewContextLogger(ctx, s.slog)
	if req.Id < 0 {
		err = render.InvalidArgumentRange("id")
		return
	}
	if util.IsEmpty(req.Name) {
		err = render.ArgumentEmpty("name")
		return
	}
	if !sharedVld.IsOfferCategory(req.OfferCategory) {
		err = render.InvalidArgumentValue("offer_category")
		return
	}
	if !sharedVld.IsOfferType(req.OfferType) {
		err = render.InvalidArgumentValue("offer_type")
		return
	}
	if req.NeedVerifyQualification {
		if !sharedVld.IsQualifyTypeArray(req.QualifyTypes, false) {
			err = render.InvalidArgumentValue("qualify_types")
			return
		}
	}
	if req.Price < 0 {
		err = render.InvalidArgumentRange("price")
		return
	}
	if req.Quota < 0 {
		err = render.InvalidArgumentRange("quota")
		return
	}
	if req.OffMaximum < 0 {
		err = render.InvalidArgumentRange("off_maximum")
		return
	}
	if !sharedVld.IsCouponUsePeriodType(req.UsePeriodType) {
		err = render.InvalidArgumentValue("use_period_type")
		return
	}
	if !util.IsEmpty(req.DateChooseType) && !sharedVld.IsChooseType(req.DateChooseType) {
		err = render.InvalidArgumentValue("date_choose_type")
		return
	}
	if !sharedVld.IsOfferUseSceneArray(req.UseScenes, false) {
		err = render.InvalidArgumentValue("use_scenes")
		return
	}
	if !sharedVld.IsScope(req.Scope) {
		err = render.InvalidArgumentValue("scope")
		return
	}
	if req.Maximum < 0 {
		err = render.InvalidArgumentRange("maximum")
		return
	}
	if req.MaxiumGotFrequency < 0 {
		err = render.InvalidArgumentRange("maxium_got_frequency")
		return
	}

	ptr = &coupon.UpdateCouponParam{
		CouponID:                req.Id,
		Name:                    req.Name,
		Desc:                    req.Desc,
		Tags:                    req.Tags,
		OfferCategory:           req.OfferCategory,
		OfferType:               req.OfferType,
		Bg:                      req.Bg,
		NeedVerifyQualification: req.NeedVerifyQualification,
		Price:                   req.Price,
		Quota:                   req.Quota,
		OffMaximum:              req.OffMaximum,
		UsePeriodType:           req.UsePeriodType,
		UseTimeRanges:           sharedConv.ConvTimeRangeArrayPbToEntity(req.UseTimeRanges),
		DateChooseType:          req.DateChooseType,
		Weekdays:                req.Weekdays,
		Monthdays:               req.Monthdays,
		UseScenes:               req.UseScenes,
		Scope:                   req.Scope,
		Maximum:                 req.Maximum,
		MaxiumGotFrequency:      req.MaxiumGotFrequency,
	}

	if req.NeedVerifyQualification {
		ptr.QualifyTypes = req.QualifyTypes
	}
	switch sqlc.EmCouponUsePeriodType(req.UsePeriodType) {
	case sqlc.EmCouponUsePeriodTypeSinceGot:
		ptr.Days = req.Days
		ptr.AvailableAfterGotDays = req.AvailableAfterGotDays
	case sqlc.EmCouponUsePeriodTypeFixedDate:
		ptr.UseBegined = sqlc.PBTimestampToGoTime(req.UseBegined)
		ptr.UseEnded = sqlc.PBTimestampToGoTime(req.UseEnded)
	}

	itemCategoryConfPtrs = sharedConv.ConvItemCategoryConfigurationPtrArrayPbToEntity(req.ItemCategoryConfs)
	itemConfPtrs = sharedConv.ConvItemConfigurationPtrArrayPbToEntity(req.ItemConfs)

	slog.Infof("coupon_imp/cmd_vld.VldUpdateCouponReq ok")
	return
}

// VldPublishCouponReq 验证发布优惠券请求
func (s *CouponWebApiImp) VldPublishCouponReq(ctx context.Context, q *sqlc.Queries, req *couponGrpc.PublishCouponReq) (ptr *coupon.UpdateCouponStatusParam, err error) {
	slog := util.NewContextLogger(ctx, s.slog)
	if req.Id < 0 {
		err = render.InvalidArgumentRange("id")
		return
	}
	ptr = &coupon.UpdateCouponStatusParam{
		CouponID: req.Id,
	}
	slog.Infof("coupon_imp/cmd_vld.VldPublishCouponReq ok")
	return
}

// VldPauseCouponReq 验证暂停优惠券请求
func (s *CouponWebApiImp) VldPauseCouponReq(ctx context.Context, q *sqlc.Queries, req *couponGrpc.PauseCouponReq) (ptr *coupon.UpdateCouponStatusParam, err error) {
	slog := util.NewContextLogger(ctx, s.slog)
	if req.Id < 0 {
		err = render.InvalidArgumentRange("id")
		return
	}
	ptr = &coupon.UpdateCouponStatusParam{
		CouponID: req.Id,
	}
	slog.Infof("coupon_imp/cmd_vld.VldPauseCouponReq ok")
	return
}

// VldPauseCouponReq 验证恢复优惠券请求
func (s *CouponWebApiImp) VldResumeCouponReq(ctx context.Context, q *sqlc.Queries, req *couponGrpc.ResumeCouponReq) (ptr *coupon.UpdateCouponStatusParam, err error) {
	slog := util.NewContextLogger(ctx, s.slog)
	if req.Id < 0 {
		err = render.InvalidArgumentRange("id")
		return
	}
	ptr = &coupon.UpdateCouponStatusParam{
		CouponID: req.Id,
	}
	slog.Infof("coupon_imp/cmd_vld.VldResumeCouponReq ok")
	return
}
